<?php
// Copyright 2019 Hackware SpA <human@hackware.cl>
// Part of "Hackware Web Services Core", released under the MIT License terms.

namespace Hawese\Core\Providers;

use Hawese\Core\User;
use Hawese\Core\Exceptions\ModelObjectNotFoundException;
use Illuminate\Contracts\Auth\Access\Gate;
use Illuminate\Support\ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    public function register()
    {
        $this->app['gate'] = $this->app[Gate::class];
    }

    /**
     * We can authenticate through the following methods.
     *
     * Every authentication method uses a server session with its
     * corresponding session cookie.
     *
     * - current session contains `user_uid`. Already logged in user.
     * - `auth_token` cookie, when user logins with "remember me" true.
     * - `Authorization: Bearer` header, does not "remember".
     * - `auth_token` POST or GET param, does not "remember", unsafe.
     *
     * All token based methods use the format `key:secret`.
     */
    public function boot()
    {
        $this->app['auth']->viaRequest('api', function ($request) {
            if ($this->app['session']->has('user_uid')) {
                $user_uid = $this->app['session']->get('user_uid');
            } else {
                $remember = false;
                if ($request->hasCookie('auth_token')) {
                    $auth_token = $request->cookie('auth_token');
                    $remember = true;
                } elseif ($request->hasHeader('Authorization')) {
                    $auth_token = $request->bearerToken();
                // GET || POST, avoid this method, specially through GET
                } elseif ($request->has('auth_token')) {
                    $auth_token = $request->input('auth_token');
                } else {
                    return null;
                }

                list($key, $secret) = explode(':', $auth_token);
            }

            try {
                if (isset($user_uid)) {
                    $user = User::find($user_uid);
                } else {
                    $user = User::loginByToken($key, $secret, $remember);
                }
            } catch (ModelObjectNotFoundException $e) {
                $user = null;
            }
            return $user;
        });

        // SuperUser can do anything
        $this->app['gate']->before(function (User $user, $ability) {
            if ($user->isSuperUser()) {
                return true;
            }
        });
    }
}
